import socket
import serial
import threading
import time
import json
import logging
from queue import Queue
from collections import defaultdict

# 配置日志
logging.basicConfig(
    level=logging.DEBUG,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('serial_server.log'),
        logging.StreamHandler()
    ]
)
logger = logging.getLogger('MultiSerialServer')

class SerialBridge:
    def __init__(self, config):
        self.config = config
        self.serial_port = None
        self.tcp_server = None
        self.client_pools = {}
        self.running = False
        self.serial_reader_thread = None
        self.tcp_threads = []
        self.init_serial()
        
        # 统计信息
        self.stats = {
            'bytes_sent': 0,
            'bytes_received': 0,
            'clients_connected': 0,
            'clients_disconnected': 0,
            'start_time': time.time()
        }

    def init_serial(self):
        try:
            self.serial_port = serial.Serial(
                port=self.config['serial_port'],
                baudrate=self.config['baudrate'],
                bytesize=self.config['bytesize'],
                parity=self.config['parity'],
                stopbits=self.config['stopbits'],
                timeout=1  # 非阻塞读取
            )
            logger.info(f"串口 {self.config['serial_port']} (TCP:{self.config['tcp_port']}) 已打开")
        except Exception as e:
            logger.error(f"打开串口 {self.config['serial_port']} 失败: {str(e)}")
            raise

    def start(self):
        self.running = True
        # 启动串口读取线程
        self.serial_reader_thread = threading.Thread(target=self._serial_reader)
        self.serial_reader_thread.daemon = True
        self.serial_reader_thread.start()
        
        # 启动TCP服务器
        self.tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.tcp_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.tcp_server.bind(('0.0.0.0', self.config['tcp_port']))
        self.tcp_server.listen(5)
        logger.info(f"TCP服务器启动在端口 {self.config['tcp_port']} (串口: {self.config['serial_port']})")
        
        # 接受客户端连接
        tcp_thread = threading.Thread(target=self._accept_clients)
        tcp_thread.daemon = True
        tcp_thread.start()
        self.tcp_threads.append(tcp_thread)
        
        # 启动统计线程
        stat_thread = threading.Thread(target=self._report_stats)
        stat_thread.daemon = True
        stat_thread.start()

    def stop(self):
        self.running = False
        # 关闭所有客户端连接
        for client_id, client_data in list(self.client_pools.items()):
            self._close_client(client_id)
        
        # 关闭TCP服务器
        if self.tcp_server:
            self.tcp_server.close()
        
        # 关闭串口
        if self.serial_port and self.serial_port.is_open:
            self.serial_port.close()
        
        logger.info(f"串口服务器 {self.config['serial_port']} (TCP:{self.config['tcp_port']}) 已停止")

    def _accept_clients(self):
        while self.running:
            try:
                client_socket, addr = self.tcp_server.accept()
                client_id = f"{addr[0]}:{addr[1]}"
                
                # 检查最大连接数
                if len(self.client_pools) >= self.config['max_clients']:
                    logger.warning(f"{self.config['serial_port']}: 达到最大连接数({self.config['max_clients']})，拒绝 {client_id}")
                    client_socket.close()
                    continue
                
                # 设置客户端超时
                client_socket.settimeout(self.config['client_timeout'])
                
                # 创建客户端数据队列
                client_queue = Queue()
                self.client_pools[client_id] = {
                    'socket': client_socket,
                    'queue': client_queue,
                    'last_active': time.time(),
                    'active': True
                }
                
                # 更新统计
                self.stats['clients_connected'] += 1
                
                # 启动客户端处理线程
                client_thread = threading.Thread(
                    target=self._handle_client,
                    args=(client_id,)
                )
                client_thread.daemon = True
                client_thread.start()
                self.tcp_threads.append(client_thread)
                
                logger.info(f"{self.config['serial_port']}: 客户端 {client_id} 已连接")
                
            except Exception as e:
                if self.running:
                    logger.error(f"接受客户端连接错误: {str(e)}")

    def _handle_client(self, client_id):
        client_data = self.client_pools.get(client_id)
        if not client_data:
            return
        
        try:
            while self.running and client_data['active']:
                # 检查超时
                if time.time() - client_data['last_active'] > self.config['client_timeout']:
                    logger.info(f"{self.config['serial_port']}: 客户端 {client_id} 超时断开")
                    break
                
                # 处理TCP到串口的数据
                try:
                    data = client_data['socket'].recv(1024)
                    if not data:
                        break
                    client_data['last_active'] = time.time()
                    self.serial_port.write(data)
                    self.stats['bytes_received'] += len(data)
                    if self.config.get('debug', False):
                        logger.debug(f"{self.config['serial_port']}: {client_id} -> 串口: {data.hex()}")
                except socket.timeout:
                    continue
                except Exception as e:
                    logger.error(f"{self.config['serial_port']}: 从客户端 {client_id} 接收错误: {str(e)}")
                    break
                
                # 处理串口到TCP的数据
                while not client_data['queue'].empty():
                    serial_data = client_data['queue'].get()
                    try:
                        client_data['socket'].sendall(serial_data)
                        self.stats['bytes_sent'] += len(serial_data)
                        if self.config.get('debug', False):
                            logger.debug(f"{self.config['serial_port']}: 串口 -> {client_id}: {serial_data.hex()}")
                    except Exception as e:
                        logger.error(f"{self.config['serial_port']}: 发送到客户端 {client_id} 错误: {str(e)}")
                        break
        finally:
            self._close_client(client_id)

    def _serial_reader(self):
        while self.running and self.serial_port and self.serial_port.is_open:
            try:
                # 读取串口数据
                data = self.serial_port.read(self.serial_port.in_waiting or 1)
                if data:
                    # 分发数据到所有客户端
                    for client_id, client_data in list(self.client_pools.items()):
                        if client_data['active']:
                            client_data['queue'].put(data)
            except Exception as e:
                logger.error(f"{self.config['serial_port']}: 读取串口错误: {str(e)}")
                time.sleep(1)

    def _close_client(self, client_id):
        if client_id in self.client_pools:
            client_data = self.client_pools.pop(client_id)
            try:
                if client_data['socket']:
                    client_data['socket'].close()
            except:
                pass
            self.stats['clients_disconnected'] += 1
            logger.info(f"{self.config['serial_port']}: 客户端 {client_id} 已断开")

    def _report_stats(self):
        """定期报告统计信息"""
        while self.running:
            time.sleep(60)  # 每分钟报告一次
            uptime = time.time() - self.stats['start_time']
            logger.info(
                f"{self.config['serial_port']} 统计: "
                f"运行 {int(uptime//3600)}h {int((uptime%3600)//60)}m, "
                f"发送 {self.stats['bytes_sent']} 字节, "
                f"接收 {self.stats['bytes_received']} 字节, "
                f"活跃客户端 {len(self.client_pools)}"
            )

def load_config(config_file):
    with open(config_file, 'r', encoding='utf-8') as f:
        configs = json.load(f)
    
    # 检查配置是否是列表
    if not isinstance(configs, list):
        raise ValueError("配置文件应该是一个串口配置的列表")
    
    # 为每个配置设置默认值
    for config in configs:
        config.setdefault('bytesize', 8)
        config.setdefault('parity', 'N')
        config.setdefault('stopbits', 1)
        config.setdefault('client_timeout', 30)
        config.setdefault('max_clients', 5)
        config.setdefault('debug', False)
        
        # 转换串口参数
        parity_map = {'N': serial.PARITY_NONE, 'E': serial.PARITY_EVEN, 'O': serial.PARITY_ODD}
        config['parity'] = parity_map.get(config['parity'], serial.PARITY_NONE)
        
        stopbits_map = {1: serial.STOPBITS_ONE, 2: serial.STOPBITS_TWO}
        config['stopbits'] = stopbits_map.get(config['stopbits'], serial.STOPBITS_ONE)
    
    return configs

def main():
    bridges = []
    
    try:
        # 加载配置文件
        configs = load_config('serial_config.json')
        logger.info(f"加载了 {len(configs)} 个串口配置")
        
        # 创建并启动所有桥接服务
        for config in configs:
            try:
                bridge = SerialBridge(config)
                bridge.start()
                bridges.append(bridge)
            except Exception as e:
                logger.error(f"启动串口 {config.get('serial_port', '未知')} 失败: {str(e)}")
        
        if not bridges:
            logger.error("没有有效的串口配置，程序退出")
            return
        
        logger.info("所有串口服务器已启动，按 Ctrl+C 停止")
        
        # 主循环
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        logger.info("收到中断信号，停止所有服务器")
    except Exception as e:
        logger.error(f"服务器错误: {str(e)}")
    finally:
        # 停止所有桥接服务
        for bridge in bridges:
            try:
                bridge.stop()
            except:
                pass

if __name__ == '__main__':
    main()